package com.csw.android.dev_utils.views

import android.content.Context
import android.graphics.Color
import android.graphics.Point
import android.graphics.Rect
import android.os.SystemClock
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ViewGroup
import androidx.annotation.Keep
import androidx.cardview.widget.CardView
import com.csw.android.dev_utils.handler.MainHandler
import com.csw.android.dev_utils.log.LogViewFragment
import com.csw.android.dev_utils.utils.ScreenInfo
import java.lang.Integer.max
import java.lang.Integer.min
import kotlin.math.abs
import kotlin.math.pow
import kotlin.math.sqrt

@Keep
class FloatWindowLayout @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : CardView(context, attrs) {
    private var animationRate = ScreenInfo.WIDTH / 1//动画速度(像素/秒)，按照一屏幕宽度的距离一秒来算
    private var dragging = false
    private var activeAreaRect = Rect()
    private var alignAnimator: AlignAnimator? = null
    var onWindowOffsetUpdate: ((Int, Int) -> Unit)? = null

    private var gestureDetector = GestureDetector(context,
        object : GestureDetector.SimpleOnGestureListener() {
            override fun onDown(e: MotionEvent): Boolean {
                alignAnimator?.interrupt()
                alignAnimator = null
                refreshActiveArea()
                dragging = false
                return true
            }

            override fun onSingleTapUp(e: MotionEvent): Boolean {
                return performClick()
            }

            override fun onScroll(
                e1: MotionEvent?,
                e2: MotionEvent,
                distanceX: Float,
                distanceY: Float
            ): Boolean {
                dragging = true
                e2.run {
                    refreshPosition(rawX, rawY)
                }
                return true
            }

        }
    )

    override fun onTouchEvent(event: MotionEvent): Boolean {
        gestureDetector.onTouchEvent(event)
        event.run {
            when (action) {
                MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                    if (dragging) {
                        refreshPosition(rawX, rawY)
                        animateToAlignBounds(rawX, rawY)
                        dragging = false
                    }
                }
            }
        }
        return true
    }

    /**
     * 刷新可活动区域
     */
    private fun refreshActiveArea() {
        activeAreaRect.set(0, 0, 0, 0)
        parent?.let {
            if (it is ViewGroup) {
                val xyInScreen = IntArray(2)
                it.getLocationOnScreen(xyInScreen)
                val halfW = width / 2
                val halfH = height / 2
                val horizontalMargin = layoutParams.let { lp ->
                    if (lp is MarginLayoutParams) {
                        lp.leftMargin + lp.rightMargin
                    } else {
                        0
                    }
                }
                val verticalMargin = layoutParams.let { lp ->
                    if (lp is MarginLayoutParams) {
                        lp.topMargin + lp.bottomMargin
                    } else {
                        0
                    }
                }
                activeAreaRect.set(
                    xyInScreen[0] + it.paddingLeft + halfW,
                    xyInScreen[1] + it.paddingTop + halfH,
                    xyInScreen[0] + it.width - it.paddingRight - halfW - horizontalMargin,
                    xyInScreen[1] + it.height - it.paddingBottom - halfH - verticalMargin,
                )
            }
        }
    }

    /**
     * 刷新窗口位置
     * @param rawX 目标点在屏幕中的横坐标位置
     * @param rawY 目标点在屏幕中的纵坐标位置
     */
    private fun refreshPosition(rawX: Float, rawY: Float) {
        val targetX = min(activeAreaRect.right, max(activeAreaRect.left, rawX.toInt()))
        val targetY = min(activeAreaRect.bottom, max(activeAreaRect.top, rawY.toInt()))
        onWindowOffsetUpdate?.invoke(
            targetX - activeAreaRect.left,
            targetY - activeAreaRect.top
        )
    }

    /**
     * 通过动画平移到边界
     * @param rawX 目标点在屏幕中的横坐标位置
     * @param rawY 目标点在屏幕中的纵坐标位置
     */
    private fun animateToAlignBounds(rawX: Float, rawY: Float) {
        val targetX = min(activeAreaRect.right, max(activeAreaRect.left, rawX.toInt()))
        val targetY = min(activeAreaRect.bottom, max(activeAreaRect.top, rawY.toInt()))
        val startX = targetX - activeAreaRect.left
        val startY = targetY - activeAreaRect.top
        var endX = if (startX > activeAreaRect.width() / 2) activeAreaRect.width() else 0
        var endY = if (startY > activeAreaRect.height() / 2) activeAreaRect.height() else 0
        if (abs(endY - startY) < abs(endX - startX)) {
            //Y的变化量小于X，吸附到上下边界，X不改
            endX = startX
        } else {
            endY = startY
        }
        alignAnimator = AlignAnimator(startX, endX, startY, endY)
        alignAnimator?.start()
    }

    private inner class AlignAnimator(
        val startX: Int,
        val endX: Int,
        val startY: Int,
        val endY: Int,
    ) {
        private val mainHandler = MainHandler()
        private var startTime = 0L
        private var duration = 500L
        var isEnd = false
            private set
        private val calcAndUpdateTask = object : Runnable {
            override fun run() {
                if (!isEnd) {
                    var progress = if (duration > 0L) {
                        (SystemClock.elapsedRealtime() - startTime) * 1f / duration
                    } else {
                        1f
                    }
                    if (progress > 1) {
                        progress = 1f
                    } else if (progress < 0) {
                        progress = 0f
                    }
                    LogViewFragment.floatWindowOffset.postValue(
                        Point(
                            (startX + (endX - startX) * progress).toInt(),
                            (startY + (endY - startY) * progress).toInt(),
                        )
                    )
                    if (progress >= 1f) {
                        isEnd = true
                    }
                    if (!isEnd) {
                        mainHandler.post(this)
                    }
                }
            }
        }

        fun start() {
            isEnd = false
            mainHandler.removeCallbacks(calcAndUpdateTask)
            startTime = SystemClock.elapsedRealtime()
            val distance = sqrt(
                (endX - startX).toDouble().pow(2.toDouble())
                        + (endY - startY).toDouble().pow(2.toDouble())
            )
            duration = (distance * 1000f / animationRate).toLong()
            mainHandler.post(calcAndUpdateTask)
        }

        fun interrupt() {
            isEnd = true
            mainHandler.removeCallbacks(calcAndUpdateTask)
        }
    }
}